﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using TVH.Comum.Db;
using TVH.Comum;
using System.Reflection;
using System.Globalization;
using System.ComponentModel;

namespace TVH.Base.Persistencia
{
    public static class GenericMake
    {
        /// <summary>
        /// Cache que contem as propriedades dos tipos e seus respectivos campos (decorator)
        /// </summary>
        public static DecoratorCache Cache = new DecoratorCache();

        public static T Make<T>(IDataReader reader)
        {
            var instance = Activator.CreateInstance<T>();
            Type tipo = typeof(T);
            foreach (var coluna in Cache[typeof(T)])
            {
                if (reader.HasColumn(coluna.AtributoColuna.NomeColuna))
                {
                    var value = reader[coluna.AtributoColuna.NomeColuna] == DBNull.Value ? null : reader[coluna.AtributoColuna.NomeColuna];
                    coluna.Propriedade.SetValue(instance, value);
                }
            }
            return instance;
        }

        public static void SetValue(this PropertyInfo property, object instancia, object value)
        {
            if (Convert.IsDBNull(value) || value == null)
            {
                if (property.PropertyType.IsValueType)
                {
                    if (property.PropertyType == typeof(DateTime))
                    {
                        value = default(DateTime);
                    }
                    else if (property.PropertyType == typeof(bool))
                    {
                        value = default(bool);
                    }
                    else
                    {
                        object testeDeValor = Activator.CreateInstance(property.PropertyType);
                        value = testeDeValor;
                    }

                    property.SetValue(instancia, value, null);
                }
            }
            else
            {

                if (property.PropertyType.IsGenericType &&
                    property.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))
                    )
                {
                    if (!property.PropertyType.GetGenericArguments()[0].Equals(value.GetType()))
                    {
                        value = CreateTypeConverter(value.GetType()).ConvertTo(value, property.PropertyType.GetGenericArguments()[0]);
                    }
                    NullableConverter conversor = new NullableConverter(property.PropertyType);
                    value = conversor.ConvertFrom(value);
                }
                else if (property.PropertyType != value.GetType() &&
                        property.PropertyType.IsValueType &&
                        value.GetType().IsValueType)
                {
                    if (property.PropertyType.IsEnum)
                    {
                        value = Enum.Parse(property.PropertyType, value.ToString());
                    }
                    else
                    {
                        value = Convert.ChangeType(value, property.PropertyType);
                    }
                }

                property.SetValue(instancia, value, null);
            }
        }

        private static TypeConverter CreateTypeConverter(Type t)
        {
            return (TypeConverter)Assembly.GetAssembly(typeof(TypeConverter)).CreateInstance(string.Format("System.ComponentModel.{0}Converter", t.Name));
        }

    }
}
